#include <msp430x16x.h>
#include <signal.h>

#include "coms.h"

#include "../main.h"
#include "../sd/sd.h"

/*
  interrupt(USART1RX_VECTOR) receivetrigger() triggers when receiving a character
  interrupt(USART1TX_VECTOR) transmittrigger() triggers once the transmit buffer empties
  comsInit(..) initialises the USART for COMS
  comsSend(..) sends a character to the modem and waits for a reply
  modInit(..) sends the modem setup commands
  modENQ0(..) checks the status of the modem
  modTransmit(..) sends a data character to the modem for transmission
*/

interrupt(USART1RX_VECTOR) receivetrigger() /* May need to implement start edge detection */
{
  unsigned char coms_error; /* Should be global */
  
  if(U1RCTL & RXWAKE) mod_rec = 1; /* Address character received */
  else mod_rec = 2; /* Data character received */
  
  coms_error = U1RCTL & (FE | PE | OE | BRK | RXERR); /* Read error flags */
  mod_out = U1RXBUF; /* Read received character */
  
  U1RCTL &= ~URXWIE; /* Receive data and address characters */
}

interrupt(USART1TX_VECTOR) transmittrigger()
{
}

void comsInit(void)
{
  /* Set P3.6/P3.7 as transmit/receive pins */
  P3SEL |=  0xC0; /* P3.6/P6.7 to TXD data out / RXD data in */
  P3DIR |=  0x40; /* P3.6 to output */
  P3DIR &= ~0x80; /* P3.7 to input */

  /* Set P6.6 low to enable transceiver interface */
  P6SEL &= ~0x40; /* P6.6 to 3.3V I/O */
  P6DIR |=  0x40; /* P6.6 to output */
  P6OUT &= ~0x40; /* P6.6 to 0 */

  /* Set P4.6 low to enable +5V_SW power */
  P4SEL &= ~0x40; /* P4.6 to 3.3V I/O */
  P4DIR |=  0x40; /* P4.6 to output */
  P4OUT &= ~0x40; /* P4.6 to 0 */

  /* Initialise USART1 settings */
  U1CTL = (CHAR | SWRST | MM); /* Set SWRST, CHAR = 8 bit char length, MM = Address-Bit multiprocessor format */
  U1TCTL = SSEL1; /* Use SMCLK for BRCLK source */
  U1RCTL = URXEIE; /* Allow erroneous chars to be received */
  U1BR0 = 0x4F; /* Baud Rate - 9600Bd with 737,280Hz SMCLK */
  U1BR1 = 0x00; /* Baud Rate - 9600Bd with 737,280Hz SMCLK */
  U1MCTL = 0x4A; /* Modulation control - 9600Bd with 737,280Hz SMCLK */
  ME2 |= (UTXE1 | URXE1); /* Enables USART1 transmit/receive modules */
  U1CTL &= ~SWRST; /* Clear SWRST */
  IE2 |= URXIE1; /* Enables URXIFG1 interrupt */
  IE2 &= ~UTXIE1; /* Disables UTXIFG1 interrupt */
}

/* Type 1 = address, 2 = data */
int comsSend(unsigned char mod_in, int sendtype, int replytype, unsigned char replychar)
{
  unsigned long int mod_timeout;
  
  while((IFG2 & UTXIFG1) == 0) { } /* Wait until transmit buffer is empty */
  
  if(replytype == 1) U1RCTL |= URXWIE; /* Receive only address characters if recaddress=1 */
  else U1RCTL &= ~URXWIE; /* Receive only data characters if recaddress=0 */
  
  if(sendtype == 1) U1TCTL |= (TXWAKE); /* Next character sent is an address if address=1 */
  U1TXBUF = mod_in; /* Sends char mod_in */
  
  /* Wait for reply, currently ignores replies of wrong type */
  for(mod_timeout=0, mod_rec=0; ; mod_timeout++)
  {
    if(mod_rec == replytype) break; /* Check for correct character type */
    if(mod_timeout>MODEM_TIMEOUT) return 2; /* If modem times out return error */
  }
  
  if(mod_out==WAKAK && replychar!=WAKAK) return 3; /* If reply is an unexpected WAKAK return error */
  if(mod_out!=replychar) return 1; /* If not expected reply then return error */
  
  return 0;
}

int modInit() /* Returns 1 = wrong character received, 2 = time out */
{  
  int i=0, status;
  unsigned char config[7] = { 0xCE, 0xA0, 0xB2, 0x80, 0x40, 0x80, 0x04 }; /* Config data from mod_int.py */
  
  /* Wake up the modem first */
  status = comsSend(WAKE,1,1,WAKAK);
  if(status!=0) return status;
  
  for(i=0; i<7; i++)  /* Run through configuration of each setting */
  {   
    status = comsSend(i,1,1,ACK); /* Send CFG command character */
    if(status!=0) return status;
    
    status = comsSend(config[i],0,1,ACK); /* Send config data character */
    if(status!=0) return status;
  }
  
  return 0;
}

int modENQ0() /* Returns 1 = wrong character received, 2 = time out */
{
  int status;
  long int mod_timeout;

  status = comsSend(ENQ0,1,1,RQD); /* Send enquire command */
  if(status!=0) return status;
  
  /* Wait for data */
  for(mod_timeout=0, mod_rec=0; ; mod_timeout++)
  {
    if(mod_rec == 2) break; /* Check for data character */
    if(mod_timeout>MODEM_TIMEOUT) return 2; /* If modem times out return error */
  }
  
  mod_rec = 0; /* Reset data received flag so the main loop doesn't trigger a mode change */
  mod_status = mod_out; /* Store modem status globally */
  
  return 0;
}

int modTransmit(unsigned char sendchar)
{
  int status;
  
  status = comsSend(sendchar,0,1,ACK); /* Send character as data */
  if(status!=0) return status;
  
  return 0;
}
